package com.appkubes.fintech.admin.application.bill.service.impl;

import com.appkubes.fintech.admin.application.bill.entity.dto.RepayVO;
import com.appkubes.fintech.admin.application.bill.enums.RentBillEnums;
import com.appkubes.fintech.admin.application.bill.enums.RentBuyEnums;
import com.appkubes.fintech.admin.application.bill.enums.RentOrderEnums;
import com.appkubes.fintech.admin.application.bill.service.IRePayOrderService;
import com.appkubes.fintech.admin.application.bill.service.IRepayService;
import com.appkubes.fintech.admin.application.credit.dao.CreditDao;
import com.appkubes.fintech.admin.application.credit.service.CreditService;
import com.appkubes.fintech.admin.application.order.dao.RentOrderDao;
import com.appkubes.fintech.admin.application.user.dao.UserBaseInfoDao;
import com.appkubes.fintech.common.exption.BusinessException;
import com.appkubes.fintech.common.response.Response;
import com.appkubes.fintech.core.po.*;
import com.appkubes.fintech.core.pojo.FintechRentBillHeaderMapper;
import com.appkubes.fintech.core.pojo.FintechRentBillLinesMapper;
import com.appkubes.fintech.core.pojo.FintechRentOrderMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @description: 线下还款
 * @author: xqc
 * @date: 2020/1/10 14:48
 * @params:
 * @return:
 */
@Service
@Transactional
@Slf4j
public class RepayServiceImpl implements IRepayService {
    @Resource
    private FintechRentBillHeaderMapper headerMapper;
    @Resource
    private FintechRentOrderMapper rentOrderMapper;
    @Resource
    private FintechRentBillLinesMapper linesMapper;
    @Resource
    private UserBaseInfoDao baseInfoDao;
    @Resource
    private IRePayOrderService rePayOrderService;
    @Resource
    private CreditDao creditDao;
    @Resource
    private CreditService creditService;

    @Resource
    private RentOrderDao rentOrderDao;

    public final static BigDecimal hum=new BigDecimal(100);
    @Override
    public Response payPeriod(RepayVO vo) {
        FintechRentBillHeader billHeader = headerMapper.selectByPrimaryKey(vo.getBillKey());
        FintechRentOrder rentOrder = rentOrderMapper.selectByPrimaryKey(billHeader.getOrderKey());
        FintechUserBaseInfo baseInfo = baseInfoDao.selectByPrimaryKey(billHeader.getUserKey());
        FintechRentBillLinesExample example = new FintechRentBillLinesExample();
        FintechRentBillLinesExample.Criteria criteria = example.createCriteria();
        criteria.andBillKeyEqualTo(billHeader.getBillKey());
        criteria.andPeriodEqualTo(vo.getPeriod());
        FintechRentBillLines lines = linesMapper.selectByExample(example).get(0);
        Integer breakAmt=0;
        if(vo.getBreaksAmount()!=null){
            breakAmt=vo.getBreaksAmount().multiply(hum).intValue();
        }
        BigDecimal unPayTotalAmt=new BigDecimal(lines.getUnpayAmount() + lines.getUnpayFineAmount()+lines.getUnpayInterestAmount()-breakAmt);
        if (vo.getPayAmt() != null && vo.getPayAmt().multiply(hum).compareTo(unPayTotalAmt)<0) {
            return Response.fail("还款金额不足");
        }
        if (!lines.getStatus().equals(RentBillEnums.还款中.getValue())
                && !lines.getStatus().equals(RentBillEnums.未开始.getValue())
                &&!lines.getStatus().equals(RentBillEnums.已逾期.getValue())) {
            return Response.fail("该期数已还款");
        }
        Response<FintechRentRepayOrder> response = rePayOrderService.createOrder(lines,vo, baseInfo, billHeader,3); // 保存账单
        return repayPeriod(response.getData(),rentOrder,"sysrepay",baseInfo,false,breakAmt);

    }

    @Override
    public Response payBefore(RepayVO vo) {
        FintechRentBillHeader billHeader = headerMapper.selectByPrimaryKey(vo.getBillKey());
        FintechRentOrder rentOrder = rentOrderMapper.selectByPrimaryKey(billHeader.getOrderKey());
        FintechUserBaseInfo baseInfo = baseInfoDao.selectByPrimaryKey(billHeader.getUserKey());
        Integer unPay = billHeader.getSurpAmount() + billHeader.getSurpFineAmount();
        if (vo.getPayAmt().multiply(hum).intValue() < unPay) {
            return Response.fail("还款金额不足");
        }
        Response<FintechRentRepayOrder> response = rePayOrderService.createOrder(vo, baseInfo, billHeader,4); // 保存账单
        Integer breaksAmt=0;
        if(vo.getBreaksAmount()!=null){
            breaksAmt=vo.getBreaksAmount().multiply(hum).intValue();
        }
        return  preRePay(response.getData(), rentOrder, "sys321", baseInfo,false,true,breaksAmt);
    }

    @Override
    public Response payBeforeAndBuyOut(RepayVO vo) {
        FintechRentBillHeader billHeader = headerMapper.selectByPrimaryKey(vo.getBillKey());
        FintechRentOrder rentOrder = rentOrderMapper.selectByPrimaryKey(billHeader.getOrderKey());
        FintechUserBaseInfo baseInfo = baseInfoDao.selectByPrimaryKey(billHeader.getUserKey());
        if(vo.getBreaksAmount()==null){
            vo.setBreaksAmount(BigDecimal.ZERO);
        }
        Integer breakAmount=vo.getBreaksAmount().multiply(hum).intValue();
        Integer unPayAmt = billHeader.getSurpAmount() + billHeader.getUnpayInterestAmount()
                +billHeader.getUnpayFineAmount()+rentOrder.getBuyOutAmount() -breakAmount;
        if (vo.getPayAmt().multiply(hum).intValue() < unPayAmt) {
            return Response.fail("还款金额不足");
        }
        Response<FintechRentRepayOrder> response = rePayOrderService.createOrder(vo, baseInfo, billHeader,5); // 保存账单
        return  preRePay(response.getData(), rentOrder, "sys321", baseInfo,true,true,breakAmount);
    }

    @Override
    public Response buyOut(RepayVO vo) {
        FintechRentBillHeader billHeader = headerMapper.selectByPrimaryKey(vo.getBillKey());
        FintechRentOrder rentOrder = rentOrderMapper.selectByPrimaryKey(billHeader.getOrderKey());
        FintechUserBaseInfo baseInfo = baseInfoDao.selectByPrimaryKey(billHeader.getUserKey());
        Response<FintechRentRepayOrder> response = rePayOrderService.createOrder(vo, baseInfo, billHeader,6);
        Response res= buyOutOrder(vo.getPayAmt().multiply(hum).intValue(),rentOrder,billHeader);
        if(res.getCode()!=200){
            return res;
        }
        rePayOrderService.repaySuc(response.getData().getRepayKey(),"");
        return res;
    }




    private Response repayPeriod(FintechRentRepayOrder repayOrder, FintechRentOrder rentOrder,String payTradeNo
            ,FintechUserBaseInfo baseInfo,Boolean isBefore,Integer breaksAmt) {
        FintechRentBillHeader billHeader = headerMapper.selectByPrimaryKey(repayOrder.getBillKey());
        if (Objects.isNull(billHeader)) {
            return Response.fail("账单不存在");
        }
        FintechRentBillLines line = linesMapper.selectByPrimaryKey(repayOrder.getBillLineKey());
        if (line.getStatus().equals(RentBillEnums.已提还.getValue()) || line.getStatus().equals(RentBillEnums.还款完毕.getValue()) ||
                line.getStatus().equals(RentBillEnums.逾期完成.getValue())) {
            rePayOrderService.repayErr(repayOrder.getRepayKey(),line.getPeriod().toString(),"请勿重复还款");
            return Response.fail("请勿重复还款");
        }
        Integer repayAmt = repayOrder.getPayAmt();
        repayAmt = repayBill(line, billHeader, repayAmt,isBefore,breaksAmt,billHeader.getUnpayPeriods());
        StringBuffer peroidsBuf = new StringBuffer();
        updateLines(line, peroidsBuf,false,billHeader);
        updateHeader(billHeader, repayAmt, false,breaksAmt);
        payOverOrder(rentOrder,billHeader);
        rePayOrderService.repaySuc(repayOrder.getRepayKey(),line.getPeriod().toString());
        return Response.success();
    }

    /**
     * @description: 提前还款
     * @author: xqc
     * @date: 2020/1/3 14:52
     * @params:
     * @return:
     */

    private Response preRePay(FintechRentRepayOrder repayOrder, FintechRentOrder rentOrder,String payTradeNo,FintechUserBaseInfo baseInfo
            ,Boolean isBuyOut,Boolean isBefore,Integer breaksAmt) {
        FintechRentBillHeader billHeader = headerMapper.selectByPrimaryKey(repayOrder.getBillKey());
        if (Objects.isNull(billHeader)) {
            throw new BusinessException("账单不存在");
        }
        Integer unPayAmt=0;
        if(isBuyOut) { // 判断是否买断
           unPayAmt = rentOrder.getBuyOutAmount() + billHeader.getSurpAmount() +billHeader.getUnpayInterestAmount()+billHeader.getUnpayFineAmount();
        }
        else{
            unPayAmt =  billHeader.getSurpAmount() +  +billHeader.getUnpayInterestAmount()+ billHeader.getUnpayFineAmount();
        }
        Integer amount = repayOrder.getPayAmt()+breaksAmt; // 金额转换
        if (unPayAmt > amount) {
            rePayOrderService.repayErr(repayOrder.getRepayKey(),"","还款金额不足");
            throw new BusinessException("还款金额不足");
        }

        List<FintechRentBillLines> linesList = getBillLinesByBillKey(billHeader.getBillKey());
        Integer repayAmt = amount+breaksAmt;  // 提还的加入进来
        StringBuffer periods = new StringBuffer();
        Integer unPeriods=billHeader.getUnpayPeriods();
        for (FintechRentBillLines bill : linesList) { // 填坑所有账单
            if (bill.getStatus().equals(RentBillEnums.未开始.getValue()) || bill.getStatus().equals(RentBillEnums.还款中.getValue())
                    || bill.getStatus().equals(RentBillEnums.已逾期.getValue())) {
                repayAmt = repayBill(bill, billHeader, repayAmt,isBefore,0,unPeriods);
                updateLines(bill, periods,true,billHeader);
            }
        }
        Integer changeAmt=repayAmt;
        if(isBuyOut) {
            changeAmt = repayAmt - rentOrder.getBuyOutAmount(); // 减去买断金额
        }
        updateHeader(billHeader, changeAmt, true,breaksAmt); // 更新总账单
        payOverOrder(rentOrder,billHeader);
        if(isBuyOut) {
            buyOutOrder(repayAmt, rentOrder, billHeader);
        }
        rePayOrderService.repaySuc(repayOrder.getRepayKey(),periods.toString());
        return Response.success("还款成功");
    }


    public List<FintechRentBillLines> getBillLinesByBillKey(String billKey){
        FintechRentBillLinesExample example=new FintechRentBillLinesExample();
        example.createCriteria().andBillKeyEqualTo(billKey);
        example.setOrderByClause(" period ");
        List<FintechRentBillLines> billHeadersList=linesMapper.selectByExample(example);
        return billHeadersList;
    }
    private Integer repayBill(FintechRentBillLines lines, FintechRentBillHeader header,
                              Integer amount,Boolean isBefore,Integer breaksAmt,Integer periods) {
        lines.setBreaksAmount(breaksAmt);
        if(header.getBreaksAmount()==0){
            header.setBreaksAmount(0);
        }
        header.setBreaksAmount(header.getBreaksAmount()+lines.getBreaksAmount());
        if (amount <= 0) { //金额小于零直接返回
            return amount;
        }

        if((lines.getPeriodStartDate().getTime()>new Date().getTime())&&isBefore){     //提前还款利息不还
            //提前还款利息不还
            // 剩余利息不还
            header.setSurpFineAmount(header.getSurpFineAmount() - lines.getUnpayFineAmount()); // 剩余还款金额
            header.setRepayFineAmount(header.getRepayFineAmount()+0); //还的利息
            lines.setRepayFineAmount(0);
            lines.setUnpayFineAmount(0);
        }
        else {
            // 还罚息
            if (amount <= lines.getUnpayFineAmount()) {
                Integer payAmt = lines.getUnpayFineAmount() - amount;
                lines.setUnpayFineAmount(payAmt);
                lines.setRepayFineAmount(lines.getRepayFineAmount() + amount);
                header.setSurpFineAmount(header.getSurpFineAmount() - amount); // 剩余还款金额
                header.setRepayFineAmount(header.getRepayFineAmount() + amount);
                amount = 0;
                return amount;
            }
            int payFineAmt = lines.getUnpayFineAmount();
            lines.setUnpayFineAmount(0);
            amount = amount - payFineAmt;
            lines.setRepayFineAmount(lines.getRepayFineAmount() + payFineAmt);
            header.setSurpFineAmount(header.getSurpFineAmount() - payFineAmt);
            header.setRepayFineAmount(header.getRepayFineAmount() + payFineAmt);
        }

        if((lines.getPeriodStartDate().getTime()>new Date().getTime())&&isBefore){     //提前还款利息不还
            // 剩余利息不还
            header.setSurpInterestAmount(header.getSurpInterestAmount() - lines.getUnpayInterestAmount()); // 剩余还款金额
            header.setRepayInterest(header.getRepayInterest()+0); //还的利息
            lines.setRepayInterestAmount(0);
            lines.setUnpayInterestAmount(0);
        }
        else {
            // 还利息
            if (amount <= lines.getUnpayInterestAmount()) {
                Integer payAmt = lines.getUnpayInterestAmount() - amount;
                lines.setUnpayInterestAmount(payAmt);
                lines.setRepayInterestAmount(lines.getRepayInterestAmount() + amount);
                header.setSurpInterestAmount(header.getSurpInterestAmount() - amount); // 剩余还款金额
                header.setRepayInterest(header.getRepayInterest() + amount); //还的利息
                amount = 0;
                return amount;
            }
            int payInterestAmt = lines.getUnpayInterestAmount();
            lines.setUnpayInterestAmount(0);
            amount = amount - payInterestAmt;
            lines.setRepayInterestAmount(lines.getRepayInterestAmount() + payInterestAmt);
            header.setSurpInterestAmount(header.getSurpInterestAmount() - payInterestAmt);
            header.setRepayInterest(header.getRepayInterest() + payInterestAmt);
        }
        // 还本金
        if (amount <= lines.getUnpayAmount()) {
            Integer payAmt = lines.getUnpayAmount() - amount;
            lines.setUnpayAmount(payAmt);
            lines.setRepayAmount(lines.getRepayAmount() + amount);
            header.setRepayAmount(header.getRepayAmount() + amount);
            header.setSurpAmount(header.getSurpAmount() - amount);
            amount = 0;
            return amount;
        }
        int rePayAmt = lines.getUnpayAmount();
        lines.setUnpayAmount(0);
        lines.setRepayAmount(lines.getRepayAmount() + rePayAmt);

        header.setRepayAmount(header.getRepayAmount() + rePayAmt);
        header.setSurpAmount(header.getSurpAmount() - rePayAmt);
        amount = amount - rePayAmt;
        return amount;
    }

    private FintechRentBillLines updateLines(FintechRentBillLines lines, StringBuffer periodsBuf,Boolean isBefore,FintechRentBillHeader header) {
        if (!lines.getStatus().equals(RentBillEnums.还款中.getValue()) && !lines.getStatus().equals(RentBillEnums.已逾期.getValue()) && !lines.getStatus().equals(RentBillEnums.未开始.getValue())) {
            return lines;
        }
        Integer unPayAmt=lines.getUnpayAmount() + lines.getUnpayFineAmount() +lines.getUnpayInterestAmount()-lines.getBreaksAmount();
        if (unPayAmt>0) { // 还款部分
            linesMapper.updateByPrimaryKey(lines);
            periodsBuf.append(lines.getPeriod() + ",");
            return lines;
        }
        if (lines.getStatus().equals(RentBillEnums.还款中.getValue()) || lines.getStatus().equals(RentBillEnums.未开始.getValue())) {
            lines.setPayTime(new Date());
            if(isBefore){
                lines.setStatus(RentBillEnums.已提还.getValue());
            }
            else {
                lines.setStatus(RentBillEnums.还款完毕.getValue());
            }
           updatePayNextLines(lines,header);
        } else if (lines.getStatus().equals(RentBillEnums.已逾期.getValue())) {
            lines.setPayTime(new Date());
            lines.setStatus(RentBillEnums.逾期完成.getValue());
            updatePayNextLines(lines,header);
        }
        periodsBuf.append(lines.getPeriod() + ",");
        linesMapper.updateByPrimaryKey(lines);
        return lines;
    }


    private FintechRentBillHeader updateHeader(FintechRentBillHeader header, Integer changeAmt, Boolean isBefore,Integer breaksAmt) {
        if (header.getStatus().equals(RentBillEnums.还款完毕.getValue()) //完毕不进账
                || header.getStatus().equals(RentBillEnums.已提还.getValue()) || header.getStatus().equals(RentBillEnums.逾期完成.getValue())) {
            return header;
        }

        FintechRentBillLinesExample linesExample=new FintechRentBillLinesExample();
        FintechRentBillLinesExample.Criteria linesCri=  linesExample.createCriteria();
        linesCri.andBillKeyEqualTo(header.getBillKey());
        linesCri.andPeriodEqualTo(header.getUnpayPeriods());
        FintechRentBillLines lines=linesMapper.selectByExample(linesExample).get(0);
        header.setUnpayFineAmount(lines.getUnpayFineAmount());  // 同步还款明细
        header.setUnpayInterestAmount(lines.getUnpayInterestAmount());
        header.setUnpayAmount(lines.getUnpayAmount());

        Integer surAmt=header.getSurpFineAmount()+ header.getSurpAmount()+header.getSurpInterestAmount();
        if (surAmt-breaksAmt<=0) {
            header.setUnpayAmount(0);
            header.setUnpayInterestAmount(0);
            header.setUnpayFineAmount(0);
            header.setStatus(RentBillEnums.还款完毕.getValue());
            if (isBefore) { // 提前还款标记
                header.setStatus(RentBillEnums.已提还.getValue());
            }
        }
        else if (header.getUnpayFineAmount() <= 0 && header.getStatus().equals(RentBillEnums.已逾期.getValue())) {
            header.setStatus(RentBillEnums.还款中.getValue());
        }
        else  if (header.getUnpayFineAmount() > 0) {
            header.setStatus(RentBillEnums.已逾期.getValue());
        }
        if(header.getBreaksAmount()==null){
            header.setBreaksAmount(0);
        }
        header.setBreaksAmount(header.getBreaksAmount()+breaksAmt);
        header.setUpdateTime(new Date());
        header.setRepayChangeAmount(header.getRepayChangeAmount() + changeAmt);//多余的零头处理
        headerMapper.updateByPrimaryKey(header);
        return header;
    }

    private FintechRentOrder payOverOrder(FintechRentOrder order, FintechRentBillHeader header) {
        if (header.getStatus().equals(RentBillEnums.还款完毕.getValue()) //完毕不进账
                || header.getStatus().equals(RentBillEnums.已提还.getValue()) || header.getStatus().equals(RentBillEnums.逾期完成.getValue())) {
            order.setStatus(RentOrderEnums.OVER.name());
            rentOrderMapper.updateByPrimaryKey(order);
            long time = System.currentTimeMillis() / 1000;
            log.info("begin updateMallOrder,orderKey is {}",order.getOrderKey());
            System.out.println("begin updateMallOrder,orderKey is " + order.getOrderKey());
            int mallOrderResult = rentOrderDao.updateMallOrder(order.getOrderKey(),"completed",(int)time,(int)time);
            log.info("end updateMallOrder,orderKey is {},result is {}",order.getOrderKey(),mallOrderResult);
            System.out.println("end updateMallOrder,orderKey is " + order.getOrderKey() + " result is " + mallOrderResult);
            return order;
        }
        return order;
    }

    private Response<FintechRentOrder> buyOutOrder(Integer amt, FintechRentOrder order, FintechRentBillHeader header) {
        if (order.getBuyOutAmount() < amt) {
            return Response.fail("买断金额不足");
        }
        if (!header.getStatus().equals(RentBillEnums.还款完毕.getValue()) //判断租金是否完毕
                && !header.getStatus().equals(RentBillEnums.已提还.getValue()) && !header.getStatus().equals(RentBillEnums.逾期完成.getValue())) {
            return Response.fail("账单未结清");
        }
        order.setBuyStatus(RentBuyEnums.已买断.getValue()); // 买断中
        rentOrderMapper.updateByPrimaryKey(order);
        creditService.recoverCredit(order.getUserKey(),order.getCreditAmount());
        return Response.success(order);
    }

//    @Override
//    public FintechCredit recoverCredit(FintechRentOrder order){
//        FintechCreditExample example=new FintechCreditExample();
//        example.createCriteria().andUserKeyEqualTo(order.getUserKey());
//        List<FintechCredit> creditList=creditDao.selectByExample(example);
//        if(creditList.size()<=0||order.getCreditAmount()==null){
//            return null;
//        }
//        FintechCredit credit=creditList.get(0);
//        if(credit.getFreezeAmount()==null){
//            credit.setCreditAmount(0L);
//        }
//        credit.setFreezeAmount(credit.getFreezeAmount()-order.getCreditAmount()); // 减去使用过的
//        credit.setCreditStatus(0);
//        credit.setUpdateTime(new Date());
//        creditDao.updateByPrimaryKey(credit);
//
//        return credit;
//    }

    public FintechRentBillLines nextLines(String billKey,Integer period){
        FintechRentBillLinesExample example=new FintechRentBillLinesExample();
        FintechRentBillLinesExample.Criteria criteria=example.createCriteria();
        criteria.andPeriodEqualTo(period+1);
        criteria.andBillKeyEqualTo(billKey);
        List<FintechRentBillLines> list=linesMapper.selectByExample(example);
        return list.size()>0? list.get(0):null;
    }



    public FintechRentBillLines updatePayNextLines(FintechRentBillLines lines,FintechRentBillHeader header){
        FintechRentBillLines billLines=nextLines(lines.getBillKey(),lines.getPeriod());
        if(billLines==null){
            return null;
        }
        if(Objects.equals(billLines.getStatus(),RentBillEnums.已提还.getValue())||
                Objects.equals(billLines.getStatus(),RentBillEnums.还款完毕.getValue())||
                Objects.equals(billLines.getStatus(),RentBillEnums.逾期完成.getValue())
        ){
            return updatePayNextLines(billLines,header); // 如果还款完毕 则继续轮换
        }
        billLines.setUpdateTime(new Date());
        if(Objects.equals(RentBillEnums.未开始.getValue(),billLines.getStatus())){
            billLines.setStatus(RentBillEnums.还款中.getValue());
        }
        linesMapper.updateByPrimaryKey(billLines);
        header.setUnpayAmount(billLines.getUnpayAmount());
        header.setUnpayFineAmount(billLines.getUnpayFineAmount());
        header.setUnpayPeriods(billLines.getPeriod());
        header.setUnpayDate(billLines.getPeriodEndDate());
        header.setUpdateTime(new Date());
        header.setUnpayInterestAmount(billLines.getPeriodInterestAmount());
        headerMapper.updateByPrimaryKey(header);
        return billLines;
    }
}
